# -*- coding: utf-8 -*-
# 定义类

import types


class Student(object):
    # 所有的属性通过__init__函数进行定义，格式如下
    def __init__(self, name):
        self.name = name

    # 也可以这样来定义（但是就必须有默认值了,不建议）
    no = 180


# 实例化
# 本身需要绑定的属性（在init里面一定有的）
# 固定的属性，所有实例都有
s = Student('zhangsan')
print(s.name)
# 动态绑定的属性（也叫实例属性）（init里面没有的）
# 动态绑定的属性，归该实例所有
# 实例属性比类属性优先级高
s.age = 18
print(s.age)
print(s.no)


# 访问限制
# 在变量名前加两个下划线，就变成私有变量了
class Person(object):
    def __init__(self, name, score, age) -> None:
        super().__init__()
        self.__name = name
        self.__score = score
        self.age = age

    def getName(self):
        print("私有属性" + self.__name)

    def setName(self, name):
        self.__name = name


p = Person('lengxue', 100, 50)
# 这样子访问就会报错
# print(p.__name)
# 可以采用这种方式获取
p.getName()
p.setName('zhangsan')
p.getName()

# 继承和多态
# 父类在类的括号内填入

# 获取对象的信息
# 使用type()判断对象类型
print(type(13))
print(type('123'))
print(type(p))
print("==============")


# 判断是不是一个函数
def test():
    pass


print(type(test) == types.FunctionType)

# __dict__ 获取对象所有自定义的属性和方法
print(p.__dict__)
# dir 可以看到对象所有属性和方法
print(dir(p))
# 查看对象有没有相应的属性
print(hasattr(p, '_Person__name'))


class Student1(object):
    pass


# 给实例绑定一个属性
s1 = Student1()
s1.name = 'zhangsan'
print(s1.name)


# 给实例绑定一个方法
def set_stuname(self, name):
    self.name = name


# 给实例绑定一个方法
s1.set_stuname = types.MethodType(set_stuname, s1)
s1.set_stuname('lisi')
print(s1.name)


# 使用__slots__ 插槽，限制类能添加的属性(对子类不起作用)
class Student2(object):
    def __init__(self) -> None:
        super().__init__()

    # 使用元组定义允许绑定的属性的名称
    __slots__ = ('name', 'age')


s2 = Student2()
s2.name = 'zhangsan'
# 这样就会报错
# s2.city = 'gadal'
print(s2.name)
# print(s2.city)
